package memconf

import (
	"errors"
	"fmt"
	"strconv"
	"sync"

	"github.com/astaxie/beego/config"
)

//Conf 读取配置文件
type Conf struct {
	Lock *sync.RWMutex
	M    map[string]string
}

func NewConf() *Conf {
	c := new(Conf)
	c.Lock = new(sync.RWMutex)
	c.M = map[string]string{}
	return c
}

//Set 重设指定的Key Value
func (conf *Conf) Set(key, val string) (err error) { //support section::key type in given key when using ini type.
	if len(key) == 0 {
		return errors.New("key is empty")
	}
	conf.Lock.Lock()
	defer conf.Lock.Unlock()
	conf.M[key] = val
	return
}

//String Get string value
func (conf *Conf) String(key string) (s string) { //support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same.
	conf.Lock.RLock()
	defer conf.Lock.RUnlock()
	s = conf.M[key]
	return
}

//Strings 没实现
func (conf *Conf) Strings(key string) (ss []string) { //get string slice
	return
}

//Int Get int value by key
func (conf *Conf) Int(key string) (int, error) {
	conf.Lock.RLock()
	defer conf.Lock.RUnlock()
	s := conf.M[key]
	return strconv.Atoi(s)
}

//Int64 Get int64 value by key
func (conf *Conf) Int64(key string) (int64, error) {
	conf.Lock.RLock()
	defer conf.Lock.RUnlock()
	s := conf.M[key]
	return strconv.ParseInt(s, 10, 64)
}

//Bool Get bool value by key
func (conf *Conf) Bool(key string) (bool, error) {
	conf.Lock.RLock()
	defer conf.Lock.RUnlock()
	s := conf.M[key]
	return ParseBool(s)
}

//Float Get float64 by key
func (conf *Conf) Float(key string) (float64, error) {
	conf.Lock.RLock()
	defer conf.Lock.RUnlock()
	s := conf.M[key]
	return strconv.ParseFloat(s, 64)
}

//DefaultString Get value by key, if value is not exist, return defaultValue
func (conf *Conf) DefaultString(key string, defaultVal string) string { // support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same.
	conf.Lock.RLock()
	defer conf.Lock.RUnlock()
	s, ok := conf.M[key]
	if ok {
		return s
	}
	return defaultVal
}

//DefaultStrings Not implementation
func (conf *Conf) DefaultStrings(key string, defaultVal []string) []string {
	return nil
}

//DefaultInt Get int value by key, if value is not exist, return defaultValue
func (conf *Conf) DefaultInt(key string, defaultVal int) int {
	i, err := conf.Int(key)
	if err != nil {
		return defaultVal
	}
	return i
}

//DefaultInt64 int64 value by key, if value is not exist, return defaultValue
func (conf *Conf) DefaultInt64(key string, defaultVal int64) int64 {
	i, err := conf.Int64(key)
	if err != nil {
		return defaultVal
	}
	return i
}

//DefaultBool int64 value by key, if value is not exist, return defaultValue
func (conf *Conf) DefaultBool(key string, defaultVal bool) bool {
	b, err := conf.Bool(key)
	if err != nil {
		return defaultVal
	}
	return b
}

//DefaultFloat float64 value by key, if value is not exist, return defaultValue
func (conf *Conf) DefaultFloat(key string, defaultVal float64) float64 {
	f, err := conf.Float(key)
	if err != nil {
		return defaultVal
	}
	return f
}

//DIY Not implementation
//TODO 暂没实现
func (conf *Conf) DIY(key string) (interface{}, error) {
	return nil, nil
}

//GetSection Not implementation
func (conf *Conf) GetSection(section string) (map[string]string, error) {
	return nil, nil
}

//SaveConfigFile Save config
func (conf *Conf) SaveConfigFile(filename string) error {
	return nil
}

//func NewConfig(reserve, key string) (c config.Configer, err error) {
//	conf := new(Conf)
//	return conf.Parse(key)
//}

//Parse 从关系库表中读取配置
func (conf *Conf) Parse(key string) (c config.Configer, err error) {
	return
}

//ParseData Not implementation
func (conf *Conf) ParseData(data []byte) (config.Configer, error) {
	return conf, errors.New("Not support")
}

//ParseBool 格式化布尔类型
func ParseBool(val interface{}) (value bool, err error) {
	if val != nil {
		switch v := val.(type) {
		case bool:
			return v, nil
		case string:
			switch v {
			case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "Y", "y", "ON", "on", "On":
				return true, nil
			case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "N", "n", "OFF", "off", "Off":
				return false, nil
			}
		case int8, int32, int64:
			strV := fmt.Sprintf("%s", v)
			if strV == "1" {
				return true, nil
			} else if strV == "0" {
				return false, nil
			}
		case float64:
			if v == 1 {
				return true, nil
			} else if v == 0 {
				return false, nil
			}
		}
		return false, fmt.Errorf("parsing %q: invalid syntax", val)
	}
	return false, fmt.Errorf("parsing <nil>: invalid syntax")
}
